/*
 * @Author: wangjun haodreams@163.com
 * @Date: 2025-05-01 15:38:27
 * @LastEditors: wangjun haodreams@163.com
 * @LastEditTime: 2025-05-03 14:24:58
 * @FilePath: \ch9329\ch9329.go
 * @Description: usb 串口鼠标驱动
 */
package ch9329

import (
	"errors"
	"fmt"
	"log"
	"strings"
	"sync"
	"time"

	"gitee.com/haodreams/serial"
)

const (
	CMD_GET_INFO             = 0x01 //获取芯片版本等信息 通过该命令向芯片获取版本号、USB枚举状态、键盘大小写指示灯状态等信息
	CMD_SEND_KB_GENERAL_DATA = 0x02 //发送USB键盘普通数据 通过该命令向芯片发送普通键盘数据包，模拟普通按键按下或释放动作
	CMD_SEND_KB_MEDIA_DATA   = 0x03 //发送USB键盘多媒体数据 通过该命令向芯片发送多媒体键盘数据包，模拟多媒体按键按下或释放动作
	CMD_SEND_MS_ABS_DATA     = 0x04 //发送USB绝对鼠标数据 通过该命令向芯片发送绝对鼠标数据包，模拟绝对鼠标相关动作
	CMD_SEND_MS_REL_DATA     = 0x05 //发送USB相对鼠标数据 通过该命令向芯片发送相对鼠标数据包，模拟相对鼠标相关动作
	CMD_SEND_MY_HID_DATA     = 0x06 //发送USB自定义HID设备数据 通过该命令向芯片发送自定义HID类设备数据包
	CMD_READ_MY_HID_DATA     = 0x87 //读取USB自定义HID设备数据 通过该命令从芯片读取自定义HID类设备数据包 注：PC机向芯片下传1包自定义HID数据包后，由芯片串口自动打包发送给外围串口设备
	CMD_GET_PARA_CFG         = 0x08 //获取参数配置 通过该命令向芯片获取当前参数配置信息
	CMD_SET_PARA_CFG         = 0x09 //设置参数配置 通过该命令向芯片设置当前参数配置信息
	CMD_GET_USB_STRING       = 0x0A // 获取字符串描述符配置 通过该命令向芯片获取当前所使5
	CMD_SET_USB_STRING       = 0x0B //用的USB字符串描述符配置 设置字符串描述符配置
	CMD_SET_DEFAULT_CFG      = 0x0C //恢复出厂默认配置 通过该命令将芯片的参数配置及
	CMD_RESET                = 0x0F //字符串配置信息恢复到出厂默认设置

	CtrlLeft     = 1 << 0 //左Ctrl
	ShiftLeft    = 1 << 1 //左Shift
	AltLeft      = 1 << 2 //左Alt
	WindowsLeft  = 1 << 3 //左GUI
	CtrlRight    = 1 << 4 //右Ctrl
	ShiftRight   = 1 << 5 //右Shift
	AltRight     = 1 << 6 //右Alt
	WindowsRight = 1 << 7 //右GUI

	ErrOK      = 0x00 //成功
	ErrTimeout = 0xE1 //超时
	ErrHead    = 0xE2 //包头错误
	ErrCmd     = 0xE3 //命令码错误
	ErrSum     = 0xE4 //校验和错误
	ErrPara    = 0xE5 //参数错误
	ErrOperate = 0xE6 //帧正常，执行失败
)

var ErrUnInit = errors.New("未初始化")

type Key struct {
	Spec byte //按键
	Code byte //代码
}

var errMap = map[byte]error{
	ErrOK:      errors.New("成功"),
	ErrTimeout: errors.New("超时"),
	ErrHead:    errors.New("包头错误"),
	ErrCmd:     errors.New("命令码错误"),
	ErrSum:     errors.New("校验和错误"),
	ErrPara:    errors.New("参数错误"),
	ErrOperate: errors.New("帧正常，执行失败"),
}

func GetError(code byte) error {
	if err, ok := errMap[code]; ok {
		return err
	}
	return fmt.Errorf("未知错误:%d", code)
}

var charMap = map[byte]*Key{
	'`': {Spec: 0, Code: 0x35},
	'1': {Spec: 0, Code: 0x1E},
	'2': {Spec: 0, Code: 0x1F},
	'3': {Spec: 0, Code: 0x20},
	'4': {Spec: 0, Code: 0x21},
	'5': {Spec: 0, Code: 0x22},
	'6': {Spec: 0, Code: 0x23},
	'7': {Spec: 0, Code: 0x24},
	'8': {Spec: 0, Code: 0x25},
	'9': {Spec: 0, Code: 0x26},
	'0': {Spec: 0, Code: 0x27},
	'-': {Spec: 0, Code: 0x2D},
	'=': {Spec: 0, Code: 0x2E},
	'~': {Spec: 2, Code: 0x35},
	'!': {Spec: 2, Code: 0x1E},
	'@': {Spec: 2, Code: 0x1F},
	'#': {Spec: 2, Code: 0x20},
	'$': {Spec: 2, Code: 0x21},
	'%': {Spec: 2, Code: 0x22},
	'^': {Spec: 2, Code: 0x23},
	'&': {Spec: 2, Code: 0x24},
	'*': {Spec: 2, Code: 0x25},
	'(': {Spec: 2, Code: 0x26},
	')': {Spec: 2, Code: 0x27},
	'_': {Spec: 2, Code: 0x2D},
	'+': {Spec: 2, Code: 0x2E},

	'[':  {Spec: 0, Code: 0x2F},
	']':  {Spec: 0, Code: 0x30},
	'\\': {Spec: 0, Code: 0x31},
	';':  {Spec: 0, Code: 0x33},
	'\'': {Spec: 0, Code: 0x34},
	',':  {Spec: 0, Code: 0x36},
	'.':  {Spec: 0, Code: 0x37},
	'/':  {Spec: 0, Code: 0x38},
	'{':  {Spec: 2, Code: 0x2F},
	'}':  {Spec: 2, Code: 0x30},
	'|':  {Spec: 2, Code: 0x31},
	':':  {Spec: 2, Code: 0x33},
	'"':  {Spec: 2, Code: 0x34},
	'<':  {Spec: 2, Code: 0x36},
	'>':  {Spec: 2, Code: 0x37},
	'?':  {Spec: 2, Code: 0x38},

	'a':  {Spec: 0, Code: 0x4},
	'b':  {Spec: 0, Code: 0x5},
	'c':  {Spec: 0, Code: 0x6},
	'd':  {Spec: 0, Code: 0x7},
	'e':  {Spec: 0, Code: 0x8},
	'f':  {Spec: 0, Code: 0x9},
	'g':  {Spec: 0, Code: 0xA},
	'h':  {Spec: 0, Code: 0xB},
	'i':  {Spec: 0, Code: 0xC},
	'j':  {Spec: 0, Code: 0xD},
	'k':  {Spec: 0, Code: 0xE},
	'l':  {Spec: 0, Code: 0xF},
	'm':  {Spec: 0, Code: 0x10},
	'n':  {Spec: 0, Code: 0x11},
	'o':  {Spec: 0, Code: 0x12},
	'p':  {Spec: 0, Code: 0x13},
	'q':  {Spec: 0, Code: 0x14},
	'r':  {Spec: 0, Code: 0x15},
	's':  {Spec: 0, Code: 0x16},
	't':  {Spec: 0, Code: 0x17},
	'u':  {Spec: 0, Code: 0x18},
	'v':  {Spec: 0, Code: 0x19},
	'w':  {Spec: 0, Code: 0x1A},
	'x':  {Spec: 0, Code: 0x1B},
	'y':  {Spec: 0, Code: 0x1C},
	'z':  {Spec: 0, Code: 0x1D},
	'A':  {Spec: 2, Code: 0x4},
	'B':  {Spec: 2, Code: 0x5},
	'C':  {Spec: 2, Code: 0x6},
	'D':  {Spec: 2, Code: 0x7},
	'E':  {Spec: 2, Code: 0x8},
	'F':  {Spec: 2, Code: 0x9},
	'G':  {Spec: 2, Code: 0xA},
	'H':  {Spec: 2, Code: 0xB},
	'I':  {Spec: 2, Code: 0xC},
	'J':  {Spec: 2, Code: 0xD},
	'K':  {Spec: 2, Code: 0xE},
	'L':  {Spec: 2, Code: 0xF},
	'M':  {Spec: 2, Code: 0x10},
	'N':  {Spec: 2, Code: 0x11},
	'O':  {Spec: 2, Code: 0x12},
	'P':  {Spec: 2, Code: 0x13},
	'Q':  {Spec: 2, Code: 0x14},
	'R':  {Spec: 2, Code: 0x15},
	'S':  {Spec: 2, Code: 0x16},
	'T':  {Spec: 2, Code: 0x17},
	'U':  {Spec: 2, Code: 0x18},
	'V':  {Spec: 2, Code: 0x19},
	'W':  {Spec: 2, Code: 0x1A},
	'X':  {Spec: 2, Code: 0x1B},
	'Y':  {Spec: 2, Code: 0x1C},
	'Z':  {Spec: 2, Code: 0x1D},
	'\n': {Spec: 0, Code: 0x28},
	' ':  {Spec: 0, Code: 0x2C},
	'\t': {Spec: 0, Code: 0x2B},
}

var keyMap = map[string]byte{
	"enter":  0x28,
	"esc":    0x29,
	"back":   0x2A,
	"tab":    0x2B,
	"space":  0x2C,
	"f1":     0x3a,
	"f2":     0x3b,
	"f3":     0x3c,
	"f4":     0x3d,
	"f5":     0x3e,
	"f6":     0x3f,
	"f7":     0x40,
	"f8":     0x41,
	"f9":     0x42,
	"f10":    0x43,
	"f11":    0x44,
	"f12":    0x45,
	"print":  0x46,
	"scroll": 0x47,
	"pause":  0x48,
	"power":  0x81,
	"insert": 0x49,
	"delete": 0x4c,
}

type CH9329 struct {
	serial.Serial
	recvBuf    []byte
	sendBuf    []byte
	addr       byte //默认为0
	NumLock    bool //NumLock 灯
	ScrollLock bool //ScrollLock 灯
	CapLock    bool //CapLock 灯
	Version    byte //版本号
	ok         bool
	lock       sync.Mutex
}

func NewCH9329(conn string) *CH9329 {
	m := new(CH9329)
	m.Setup(conn)
	return m
}

func (m *CH9329) Setup(conn string) {
	m.Serial.Setup(
		serial.WithConnect(conn),
		serial.WithTimeout(500),
	)
	m.recvBuf = make([]byte, 128)
	m.sendBuf = make([]byte, 128)
}

func (m *CH9329) Name() string {
	return "mkey"
}

func (m *CH9329) Open() (err error) {
	err = m.Serial.Open()
	if err != nil {
		return
	}
	m.Serial.Reset()
	err = m.Info()
	if err != nil {
		time.Sleep(time.Millisecond * 500)
		m.Serial.Reset()
		err = m.Info()
	}
	if err != nil {
		return err
	}
	return
}

func (m *CH9329) OK() bool {
	return m.ok
}

// 设置地址
func (m *CH9329) SetAddr(addr byte) {
	m.addr = addr
}

func (m *CH9329) send(cmd byte, data []byte) (err error) {
	m.sendBuf[0] = 0x57
	m.sendBuf[1] = 0xAB
	m.sendBuf[2] = m.addr
	m.sendBuf[3] = cmd
	m.sendBuf[4] = byte(len(data))
	copy(m.sendBuf[5:], data)
	n := len(data) + 5
	m.sendBuf[n] = CheckSum(m.sendBuf[:n])
	n++
	_, err = m.Write(m.sendBuf[:n])
	log.Printf("send: % 02x", m.sendBuf[:n])
	return err
}
func (m *CH9329) recv() (cmd byte, data []byte, err error) {
	_, err = m.ReafFull(m.recvBuf[:5])
	if err != nil {
		return 0, nil, err
	}
	if m.recvBuf[0] != 0x57 || m.recvBuf[1] != 0xAB {
		return 0, nil, fmt.Errorf("recv header error")
	}
	n := int(m.recvBuf[4])
	_, err = m.ReafFull(m.recvBuf[5 : n+6]) //包含校验位
	if err != nil {
		return 0, nil, err
	}
	log.Printf("recv: % 02x", m.recvBuf[:n+5])

	if CheckSum(m.recvBuf[:n+5]) != m.recvBuf[n+5] {
		return 0, nil, fmt.Errorf("checksum error")
	}

	cmd = m.recvBuf[3]
	if cmd&0x80 == 0 {
		return cmd, nil, errors.New("应答命令错误")
	}
	cmd &= 0xf
	data = m.recvBuf[5 : n+5]
	return cmd, data, err
}

// 输出版本信息
func (m *CH9329) Info() (err error) {
	err = m.send(CMD_GET_INFO, nil)
	if err != nil {
		return
	}
	cmd, data, err := m.recv()
	if err != nil {
		return
	}
	if cmd != CMD_GET_INFO {
		err = fmt.Errorf("recv cmd error, expect %d, got %d", CMD_GET_INFO, cmd)
		return
	}
	if len(data) != 8 {
		err = fmt.Errorf("recv data error, expect length= %d, got %d", 8, len(data))
		return
	}
	m.Version = data[0]
	if data[1] != 0 {
		m.ok = true
	} else {
		m.ok = false
	}
	if data[2]&1 != 0 {
		m.NumLock = true
	} else {
		m.NumLock = false
	}
	if data[2]&2 != 0 {
		m.CapLock = true
	} else {
		m.CapLock = false
	}
	if data[2]&4 != 0 {
		m.ScrollLock = true
	} else {
		m.ScrollLock = false
	}
	return
}

func (m *CH9329) Reset() (err error) {
	if !m.OK() {
		return ErrUnInit
	}
	m.lock.Lock()
	defer m.lock.Unlock()
	err = m.send(CMD_RESET, nil)
	if err != nil {
		return
	}

	cmd, data, err := m.recv()
	if err != nil {
		return
	}
	if cmd != CMD_RESET {
		err = fmt.Errorf("recv cmd error, expect %d, got %d", CMD_RESET, cmd)
		return
	}
	if len(data) != 1 {
		err = fmt.Errorf("recv data error, expect length= %d, got %d", 1, len(data))
		return
	}
	if data[0] != ErrOK {
		return GetError(data[0])
	}

	return
}

// 抖动
func (m *CH9329) Shake() (err error) {
	if !m.OK() {
		return ErrUnInit
	}
	m.lock.Lock()
	defer m.lock.Unlock()

	data := make([]byte, 5)
	data[0] = 0x1
	data[2] = 0x01
	err = m.send(CMD_SEND_MS_REL_DATA, data)
	if err != nil {
		return
	}
	typ, data, err := m.recv()
	if err != nil {
		return
	}
	if typ != CMD_SEND_MS_REL_DATA {
		err = fmt.Errorf("recv cmd error, expect %d, got %d", CMD_SEND_MS_REL_DATA, typ)
		return
	}
	if len(data) != 1 {
		err = fmt.Errorf("recv data error, expect length= %d, got %d", 1, len(data))
		return
	}
	if data[0] != ErrOK {
		return GetError(data[0])
	}
	time.Sleep(time.Millisecond * 50)
	data = make([]byte, 5)
	data[0] = 0x1
	data[2] = 0xff
	err = m.send(CMD_SEND_MS_REL_DATA, data)
	if err != nil {
		return
	}
	typ, data, err = m.recv()
	if err != nil {
		return
	}
	if typ != CMD_SEND_MS_REL_DATA {
		err = fmt.Errorf("recv cmd error, expect %d, got %d", CMD_SEND_MS_REL_DATA, typ)
		return
	}
	if len(data) != 1 {
		err = fmt.Errorf("recv data error, expect length= %d, got %d", 1, len(data))
		return
	}
	if data[0] != ErrOK {
		return GetError(data[0])
	}
	time.Sleep(time.Millisecond * 40)
	return
}

// 按下鼠标键
func (m *CH9329) PressMouseKey(key string) (err error) {
	if !m.OK() {
		return ErrUnInit
	}
	m.lock.Lock()
	defer m.lock.Unlock()

	k := byte(0)
	switch key {
	case "left":
		k = 1
	case "right":
		k = 2
	case "middle":
		k = 4
	}
	data := make([]byte, 5)
	data[0] = 0x1
	data[1] = k
	err = m.send(CMD_SEND_MS_REL_DATA, data)
	if err != nil {
		return
	}
	typ, data, err := m.recv()
	if err != nil {
		return
	}
	if typ != CMD_SEND_MS_REL_DATA {
		err = fmt.Errorf("recv cmd error, expect %d, got %d", CMD_SEND_MS_REL_DATA, typ)
		return
	}
	if len(data) != 1 {
		err = fmt.Errorf("recv data error, expect length= %d, got %d", 1, len(data))
		return
	}
	if data[0] != ErrOK {
		return GetError(data[0])
	}
	time.Sleep(time.Millisecond * 10)
	data = make([]byte, 5)
	data[0] = 0x1
	err = m.send(CMD_SEND_MS_REL_DATA, data)
	if err != nil {
		return
	}
	typ, data, err = m.recv()
	if err != nil {
		return
	}
	if typ != CMD_SEND_MS_REL_DATA {
		err = fmt.Errorf("recv cmd error, expect %d, got %d", CMD_SEND_MS_REL_DATA, typ)
		return
	}
	if len(data) != 1 {
		err = fmt.Errorf("recv data error, expect length= %d, got %d", 1, len(data))
		return
	}
	if data[0] != ErrOK {
		return GetError(data[0])
	}
	time.Sleep(time.Millisecond * 40)
	return
}

// 按下组合键
func (m *CH9329) PressKeys(keys []string) (err error) {
	if !m.OK() {
		return ErrUnInit
	}
	m.lock.Lock()
	defer m.lock.Unlock()

	opts := byte(0)
	data := make([]byte, 8)
	i := 2
	for _, key := range keys {
		key = strings.ToLower(strings.TrimSpace(key))
		switch key {
		case "ctrl":
			opts |= CtrlLeft
		case "shift":
			opts |= ShiftLeft
		case "alt":
			opts |= AltLeft
		case "windows":
			opts |= WindowsLeft
		default:
			switch len(key) {
			case 0:
				continue
			case 1:
				code, ok := charMap[key[0]]
				if ok {
					data[i] = code.Code
					i++
					continue
				}
				return fmt.Errorf("[%s] key not found", key)
			default:
				code, ok := keyMap[key]
				if ok {
					data[i] = code
					i++
					continue
				}
			}
		}
	}
	data[0] = byte(opts)
	//键
	err = m.send(CMD_SEND_KB_GENERAL_DATA, data)
	if err != nil {
		return
	}
	cmd, data, err := m.recv()
	if err != nil {
		return
	}
	if cmd != CMD_SEND_KB_GENERAL_DATA {
		err = fmt.Errorf("recv cmd error, expect %d, got %d", CMD_SEND_KB_GENERAL_DATA, cmd)
		return
	}
	if len(data) != 1 {
		err = fmt.Errorf("recv data error, expect length= %d, got %d", 1, len(data))
		return
	}
	if data[0] != ErrOK {
		return GetError(data[0])
	}
	time.Sleep(time.Millisecond * 10)

	//释放键
	err = m.send(CMD_SEND_KB_GENERAL_DATA, []byte{0, 0, 0, 0, 0, 0, 0, 0})
	if err != nil {
		return
	}
	cmd, data, err = m.recv()
	if err != nil {
		return
	}
	if cmd != CMD_SEND_KB_GENERAL_DATA {
		err = fmt.Errorf("recv cmd error, expect %d, got %d", CMD_SEND_KB_GENERAL_DATA, cmd)
		return
	}
	if len(data) != 1 {
		err = fmt.Errorf("recv data error, expect length= %d, got %d", 1, len(data))
		return
	}
	if data[0] != ErrOK {
		return GetError(data[0])
	}
	time.Sleep(time.Millisecond * 80)
	return err
}

// 按下单个键
func (m *CH9329) PressKey(key string) (err error) {
	if !m.OK() {
		return ErrUnInit
	}
	m.lock.Lock()
	defer m.lock.Unlock()

	key = strings.ToLower(strings.TrimSpace(key))
	code, ok := keyMap[key]
	if !ok {
		return fmt.Errorf("key not found")
	}
	//按键
	err = m.send(CMD_SEND_KB_GENERAL_DATA, []byte{0, 0, code, 0, 0, 0, 0, 0})
	if err != nil {
		return
	}
	cmd, data, err := m.recv()
	if err != nil {
		return
	}
	if cmd != CMD_SEND_KB_GENERAL_DATA {
		err = fmt.Errorf("recv cmd error, expect %d, got %d", CMD_SEND_KB_GENERAL_DATA, cmd)
		return
	}
	if len(data) != 1 {
		err = fmt.Errorf("recv data error, expect length= %d, got %d", 1, len(data))
		return
	}
	if data[0] != ErrOK {
		err = fmt.Errorf("recv data error, expect %d, got %d", ErrOK, data[0])
		return
	}
	time.Sleep(time.Millisecond * 10)

	//释放键
	err = m.send(CMD_SEND_KB_GENERAL_DATA, []byte{0, 0, 0, 0, 0, 0, 0, 0})
	if err != nil {
		return
	}
	cmd, data, err = m.recv()
	if err != nil {
		return
	}
	if cmd != CMD_SEND_KB_GENERAL_DATA {
		err = fmt.Errorf("recv cmd error, expect %d, got %d", CMD_SEND_KB_GENERAL_DATA, cmd)
		return
	}
	if len(data) != 1 {
		err = fmt.Errorf("recv data error, expect length= %d, got %d", 1, len(data))
		return
	}
	if data[0] != ErrOK {
		err = fmt.Errorf("recv data error, expect %d, got %d", ErrOK, data[0])
		return
	}
	time.Sleep(time.Millisecond * 80)
	return err
}

// 输入字符串
// delaysMs 延迟多少毫秒输入下个字符
func (m *CH9329) WriteString(text string, delaysMs ...int64) (err error) {
	if !m.OK() {
		return ErrUnInit
	}

	//检查num lock 灯是否亮了
	err = m.Info()
	if err != nil {
		return err
	}
	if m.CapLock {
		//如果caps lock 灯亮了，发送按键命令关闭caps lock 灯
		err = m.PressKey("caps")
		if err != nil {
			return err
		}
	}
	delay := int64(0)
	if len(delaysMs) > 0 {
		delay = delaysMs[0]
	}
	for _, c := range text {
		err = m.WriteByte(byte(c))
		if err != nil {
			return err
		}
		if delay > 0 {
			time.Sleep(time.Duration(delay) * time.Millisecond)
		}
	}
	return err
}

// 输入单个字符
func (m *CH9329) WriteByte(ch byte) (err error) {
	if !m.OK() {
		return ErrUnInit
	}
	m.lock.Lock()
	defer m.lock.Unlock()

	code, ok := charMap[ch]
	if !ok {
		return fmt.Errorf("key not found")
	}
	//释放键
	err = m.send(CMD_SEND_KB_GENERAL_DATA, []byte{code.Spec, 0, code.Code, 0, 0, 0, 0, 0})
	if err != nil {
		return
	}
	cmd, data, err := m.recv()
	if err != nil {
		return
	}
	if cmd != CMD_SEND_KB_GENERAL_DATA {
		err = fmt.Errorf("recv cmd error, expect %d, got %d", CMD_SEND_KB_GENERAL_DATA, cmd)
		return
	}
	if len(data) != 1 {
		err = fmt.Errorf("recv data error, expect length= %d, got %d", 1, len(data))
		return
	}
	if data[0] != ErrOK {
		return GetError(data[0])
	}
	time.Sleep(time.Millisecond * 10)

	//释放键
	err = m.send(CMD_SEND_KB_GENERAL_DATA, []byte{0, 0, 0, 0, 0, 0, 0, 0})
	if err != nil {
		return
	}
	cmd, data, err = m.recv()
	if err != nil {
		return
	}
	if cmd != CMD_SEND_KB_GENERAL_DATA {
		err = fmt.Errorf("recv cmd error, expect %d, got %d", CMD_SEND_KB_GENERAL_DATA, cmd)
		return
	}
	if len(data) != 1 {
		err = fmt.Errorf("recv data error, expect length= %d, got %d", 1, len(data))
		return
	}
	if data[0] != ErrOK {
		return GetError(data[0])
	}
	time.Sleep(time.Millisecond * 40)
	return err
}

func CheckSum(data []byte) byte {
	sum := byte(0)
	for _, v := range data {
		sum += v
	}
	return sum
}
